package material

import (
	"context"
	"device-admin/config/mysql"
	"device-admin/internal/dao"
	"device-admin/internal/models"
	"regexp"
	"sort"
	"strings"
	"time"

	"192.168.1.75/go-pkg/errorx"
	"github.com/samber/lo"
)

type MaterialFolder struct{}

const (
	DefaultFolderID   = "0"
	DefaultFolderName = "默认分组"
	MaxGroupCount     = 20
)

// 素材分组保存
func (MaterialFolder) Save(ctx context.Context, merchantID string, ID, name string, Type int8) (err error) {
	db := mysql.NewDB()
	if ID == DefaultFolderID {
		return errorx.New("默认分组不允许编辑", -1)
	}
	if Type < 0 || Type > 3 {
		return errorx.New("分组类型错误", -1)
	}
	// 编辑不传分类，新增必传
	if ID == "" && Type == 0 {
		return errorx.New("分组类型错误", -1)
	}

	if strings.TrimSpace(name) == "" {
		return errorx.New("分组名称不能为空", -1)
	}
	name = strings.TrimSpace(name)
	regRes, _ := regexp.MatchString("^[0-9a-zA-Z\u4e00-\u9fa5]{1,12}$", name)
	if !regRes {
		return errorx.New("分组名称仅限中文、英文及数字, 且最长12个字符", -1)
	}
	if name == DefaultFolderName {
		return errorx.New("分组名称已被占用", -1)
	}
	// 分组名称已被占用
	nameExist, err1 := dao.MaterialFolder{}.SameNameExist(ctx, db, merchantID, name, Type, ID)
	if err1 != nil {
		return err1
	}
	if nameExist {
		return errorx.New("分组名称已被占用", -1)
	}
	// 同父级的子分组数量
	_, PIDChildrenCount, _ := dao.MaterialFolder{}.List(ctx, db, merchantID, nil, Type)
	if ID == "" {
		// 最多20个分组
		if PIDChildrenCount >= MaxGroupCount {
			return errorx.New("分组数量上限20个", -1)
		}
		// 写入数据库
		dao.MaterialFolder{}.Create(ctx, db, merchantID, name, Type)
	} else {
		// 最多20个分组
		if PIDChildrenCount > MaxGroupCount {
			return errorx.New("分组数量上限20个", -1)
		}

		if ID != "0" {
			// 分组是否存在
			folderInfo, _ := dao.MaterialFolder{}.Detail(ctx, db, merchantID, ID, Type)
			if folderInfo == nil || folderInfo.ID == "" {
				return errorx.New("分组不存在", -1)
			}
		}
		// 更新数据库
		dao.MaterialFolder{}.Update(ctx, db, merchantID, ID, name, nil)
	}
	return
}

// 素材分组列表
func (MaterialFolder) List(ctx context.Context, merchantID string, Type int8) (list []*models.MaterialFolder, total int64, err error) {
	db := mysql.NewDB()
	if Type <= 0 || Type > 3 {
		return list, 0, errorx.New("分组类型错误", -1)
	}
	defaultGroup := &models.MaterialFolder{
		ID:         DefaultFolderID,
		MerchantID: merchantID,
		Name:       DefaultFolderName,
		Type:       Type,
		Sort:       0,
		CreatedAt:  time.Now().Unix(),
	}
	List, total, _ := dao.MaterialFolder{}.List(ctx, db, merchantID, nil, Type)

	sort.Slice(List, func(i int, j int) bool {
		return List[i].Sort < List[j].Sort
	})

	return append([]*models.MaterialFolder{defaultGroup}, List...), total + 1, nil
}

// 素材分组排序
func (MaterialFolder) Sort(ctx context.Context, merchantID string, Type int8, sort []struct {
	ID   string `json:"id"`
	Sort int8   `json:"sort"`
}) (err error) {
	db := mysql.NewDB()
	var FolderIDList []string
	for _, v := range sort {
		if v.ID == "" {
			return errorx.New("分组ID不能为空", -1)
		}
		if v.ID == DefaultFolderID {
			return errorx.New("默认分组不允许排序", -1)
		}
		if v.Sort < 0 {
			return errorx.New("排序值不合法", -1)
		}
		if lo.Contains(FolderIDList, v.ID) {
			return errorx.New("分组ID重复", -1)
		}
		FolderIDList = append(FolderIDList, v.ID)
	}

	// 判断分组是否存在
	_, total, _ := dao.MaterialFolder{}.List(ctx, db, merchantID, FolderIDList, Type)
	if len(FolderIDList) != int(total) {
		return errorx.New("分组不存在", -1)
	}

	for _, v := range sort {
		dao.MaterialFolder{}.Update(ctx, db, merchantID, v.ID, "", &v.Sort)
	}
	return
}

// 素材分组删除
func (MaterialFolder) Delete(ctx context.Context, merchantID string, folderID string) (err error) {
	db := mysql.NewDB()
	if folderID == "" {
		return errorx.New("分组ID不能为空", -1)
	}
	if folderID == DefaultFolderID {
		return errorx.New("默认分组不允许删除", -1)
	}

	// 查询是否存在
	folderInfo, _ := dao.MaterialFolder{}.Detail(ctx, db, merchantID, folderID, 0)
	if folderInfo == nil || folderInfo.ID == "" {
		return errorx.New("分组不存在", -1)
	}
	// 分组有素材时不允许删除
	_, materialCount := dao.Material{}.Detail(ctx, db, merchantID, "", folderID, 0, 0, -1)
	if materialCount != 0 {
		return errorx.New("分组内存在素材，请清空素材后进行删除", -1)
	}

	// 删除分组
	dao.MaterialFolder{}.Delete(ctx, db, merchantID, folderID)
	return nil
}
